
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

/**
 *
 * @author Terry
 */
public class POPConnection implements Runnable {

   
    public enum popListenState { USER, PASS, TRANSACTION, QUIT};
    
    private static final String CRLF = "\r\n";
    private popListenState fState;
    private Socket fClient;
    private BufferedReader fromClient;
    private final DataOutputStream toClient;
    private boolean isConnected;
    
    
    // added here so can be checked with password (Terry Miller)
    private String username; 
    private String password;
    private UserMail user;
    
    
    public POPConnection(Socket aClient) throws Exception
    {
        
        fClient = aClient;
        fromClient = new BufferedReader(new InputStreamReader(fClient.getInputStream()));
        toClient = new DataOutputStream(fClient.getOutputStream());
        isConnected = true;
        fState = popListenState.USER;
        returnMessage("+OK POP3 Server Ready");
 
    }
    
    public void processCommand(String mess) throws Exception
    {
        String lMessage = "";
        String message = mess.toUpperCase();
        
        if (message.toUpperCase().startsWith("USER")) {
            lMessage = processUser(message);
   
        }
     
        if(message.toUpperCase().startsWith("PASS"))
        {
            
            lMessage = processPass(message);
        }
        
        if(message.toUpperCase().startsWith("LIST"))
        {
            lMessage = processList(message);
        }
        
        if(message.toUpperCase().startsWith("RETR"))
        {
            
            lMessage = processReturn(message);
        }
        
        if(message.toUpperCase().startsWith("DEL"))
        {
             lMessage = ProcessDelete(message);
        }
        
        if(message.toUpperCase().startsWith("QUIT"))
        {
            returnMessage("+OK");
            user.save();
            close();
        }
        
        // terry added trim 
        if(lMessage.trim().isEmpty())
                lMessage = "-ERR ";
        
        returnMessage(lMessage);
        
    }
    
    public void returnMessage(String aMessage) {
        try {
            toClient.writeBytes(aMessage + CRLF);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }
    
     
    
    public String processUser(String message) throws Exception 
    {
        if(fState == popListenState.USER )
        {
           username = message.substring(4,message.length()).trim().toLowerCase();
           boolean pass = IO.checkUsername(username);
           
           if (pass)
           {
               // username correct 
                fState = popListenState.PASS;
                
                
                
                
                return  "+OK User accepted";
           }
           else
           {
               return "-ERR: Invalid Username";
           }
           
        }
        else
        { 
            return "-ERR: Unknown command";
        }
       
    }
    
    public String processPass(String message) throws Exception
    {
        
        if(fState == popListenState.PASS )
        {
            
           password = message.substring(4,message.length()).trim().toLowerCase();
       
           boolean pass = IO.checkPassword(username, password);
           
           if(pass)
           {
                user = UserMail.open(username);
                
                
                
                
                
                
                
                fState = popListenState.TRANSACTION;
                return  "+OK Pass accepted";
           }
           else
           {
               return "-ERR: Invalid Password";
           }
        }
        else
        {
             return "-ERR: Unknown command";
        }
         
    }
    
    public String processList(String message)
    {
        
        if(fState == popListenState.TRANSACTION)
        {
            for(int x =0; x < user.getMessages().size(); x++)
            {
                returnMessage((x+1) + "." + user.getMessages().get(x).
                        toString().length());
            }
            
           return ".";
        }
        else
        { 
            return "-ERR: Unknown command";
        }
         
    }
    
    public String processReturn(String message)
    {
        String sId = message.substring(4,message.length());
        
         
        if(fState == popListenState.TRANSACTION && IO.userInputInteger(sId))
        {
           int id =  Integer.parseInt(sId.trim()) -1;
           
           if(id >= 0 && id < user.size())
           {
               return user.find(id).toString();
           }
           else
           {
              return "-ERR: Unknown command";
           }
          
        }
        else
        { 
            return "-ERR: Unknown command";
        }
        
        
    }
    
    
    public String ProcessDelete(String message)
    {
        String sId = message.substring(3,message.length());
        
         
        if(fState == popListenState.TRANSACTION && IO.userInputInteger(sId))
        {
            System.out.println(" ID VALUE ");
           int id =  Integer.parseInt(sId.trim()) -1;
           
           
            
           if(id >= 0 && id < user.size())
           {
             user.delete(id);
             return ".";
           }
           else
           {
              return "-ERR: Unknown command";
           }
          
            
        
        }
        else
        { 
            return "-ERR: Unknown command";
        } 
        
    }
    
     // Close the connection. Try to send QUIT-command and then close the socket. 
    public void close() {
        isConnected = false;
        try {
            user.save();
            returnMessage("221 Bye");
            fClient.close();
        } catch (IOException e) {
            System.out.println("Unable to close connection: " + e.getMessage());
            isConnected = true;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        
    }
    
    @Override
    public void run() {
       String incoming;
        try {
            while (true) {
                incoming = fromClient.readLine();
                // terry added to uppercase 
                processCommand(incoming);
            }
        } catch (Exception ex) {
            System.out.println(ex.getMessage());

        }
    }
    
    public void finalize() throws Throwable {
        if(isConnected) { 
            close(); 
        } 
        super.finalize();
    }
    
}
